﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using CommonBehaviors.Actions;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.AreaManagement;
using Styx.CommonBot.Profiles;
using Styx.Pathing;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.World;
using Styx.WoWInternals.WoWObjects;

using Action = Styx.TreeSharp.Action;

namespace PetBuddy.Helpers
{
    public class Mover
    {
        #region Variables

        private static LocalPlayer Me = PetBuddy.Me;
        public static NavSelector navSelector = NavSelector.CRITTER;

        public enum NavSelector
        {
            CRITTER,
            STABLE,
            PROFILE,
            WAIT,
            LANDING
        }

        const int SWIFT_FLYFORM = 40120;
        const int NORMAL_FLYFORM = 33943;
        const int TRAVEL_FORM = 783;
        const int CAT_FORM = 763;


        #endregion

        #region Init
        public static void RevriteAndReLoadProfile()
        {
            if (ProfileManager.CurrentProfile.GrindArea != null)
                return;
            var newProfile = new XDocument(
                new XElement("HBProfile",
                             new XElement("Name", "_temp Profile"),
                             new XElement("MinLevel", "1"),
                             new XElement("MaxLevel", "91"),
                             new XElement("GrindArea",
                                          new XElement("TargetMinLevel", "1"),
                                          new XElement("TargetMaxLevel", "91"),
                                          new XElement("Hotspots", from el in ProfileManager.CurrentProfile.HotspotManager.Hotspots
                                                                   select new XElement("Hotspot",
                                                                                       new XAttribute("X", el.X),
                                                                                       new XAttribute("Y", el.Y),
                                                                                       new XAttribute("Z", el.Z)
                                                                       )
                                              )
                                 )
                    )
                );
            var path = Path.Combine(BotManager.BotsDirectory, "_tmpProfile.xml");
            newProfile.Save(path);
            ProfileManager.LoadNew(path, false);
        }
        #endregion

        private static WoWPoint TargetNavPoint
        {
            get {
                WoWPoint spot;
                switch (navSelector)
                {
                    case NavSelector.CRITTER:
                        return Seeker.NextBattlePetCritter.Location;

                    case NavSelector.STABLE:
                        return Stabler.NearestStableMaster.Location;

                    case NavSelector.PROFILE:
                        return ProfileManager.CurrentProfile.GrindArea.CurrentHotSpot.ToWoWPoint();

                    case NavSelector.WAIT:
                        var flyup = Me.Location.Add(0, 0, 100);
                        GameWorld.TraceLine(Me.Location, flyup,
                                            GameWorld.CGWorldFrameHitFlags.HitTestGroundAndStructures |
                                            GameWorld.CGWorldFrameHitFlags.HitTestBoundingModels,
                                            out spot);
                        return spot;

                    case NavSelector.LANDING:
                        var land = Me.Location.Add(0, 0, -1000);
                        GameWorld.TraceLine(Me.Location, land,
                                            GameWorld.CGWorldFrameHitFlags.HitTestGroundAndStructures |
                                            GameWorld.CGWorldFrameHitFlags.HitTestLiquid |
                                            GameWorld.CGWorldFrameHitFlags.HitTestLiquid2,
                                            out spot);
                        return spot;

                    default:
                        return WoWPoint.Empty;
                }
            }
        }

        public static Composite MoveToTargetNavPoint()
        {
            return new Sequence(

                new Decorator(ret => Me.Class == WoWClass.Druid,
                              new PrioritySelector(

                                  new Decorator(ret => Me.IsOutdoors && Me.Location.Distance(TargetNavPoint) > Mount.MountDistance,
                                                new PrioritySelector(

                                                    new Decorator(ret => SpellManager.HasSpell(40120) && SpellManager.CanCast(40120) && !Me.HasAura(40120),
                                                                  new Action(ret => SpellManager.CastSpellById(40120))),

                                                    new Decorator(ret => SpellManager.HasSpell(33943) && SpellManager.CanCast(33943) && !Me.HasAura(33943),
                                                                  new Action(ret => SpellManager.CastSpellById(33943))),

                                                    new Decorator(ret => !Me.Mounted,
                                                                  new Sequence(

                                                                      new Action(ret => Flightor.MountHelper.MountUp()),
                                                                      new Wait(2, ret => !Me.Mounted, new ActionIdle())
                                                                      ))
                                                    )),

                                  new Decorator(ret => Me.IsOutdoors && Me.Location.Distance(TargetNavPoint) < Mount.MountDistance
                                                       && SpellManager.HasSpell(783) && SpellManager.CanCast(783) && !Me.HasAura(783),
                                                new Action(ret => SpellManager.CastSpellById(783))
                                      ),

                                  new Decorator(ret => !Me.IsOutdoors
                                                       && SpellManager.HasSpell(763) && SpellManager.CanCast(763) && !Me.HasAura(763),
                                                new Action(ret => SpellManager.CastSpellById(763))
                                      ),

                                  new Decorator(ret => Me.Location.Distance(TargetNavPoint) > 10,
                                                new PrioritySelector(

                                                    new Decorator(ret => Me.HasAura(40120) || Me.HasAura(33943) || Me.Mounted,
                                                                  new Action(ret => Flightor.MoveTo(TargetNavPoint))),
                                                    new Decorator(ret => true,
                                                                  new Action(ret => Navigator.MoveTo(TargetNavPoint)))
                                                    ))
                                  )),

                new Decorator(ret => !Me.Mounted && Me.Location.Distance(TargetNavPoint) > Mount.MountDistance,
                              new Sequence(
                                  new Action(ret => Flightor.MountHelper.MountUp()),
                                  new Wait(2, ret => !Me.Mounted, new ActionIdle())
                                  )),

                new Decorator(ret => Me.Location.Distance(TargetNavPoint) > 12,
                              new Action(ret => Flightor.MoveTo(TargetNavPoint))
                    )
                );
        }
        
        public static Composite Dismounter()
        {
            return new PrioritySelector(

                new Decorator(ret => Me.IsMoving,
                              new Sequence(
                                  new Action(ret => WoWMovement.MoveStop()),
                                  new ActionAlwaysFail()
                                  )),

                new Decorator(ret => Me.HasAura(SWIFT_FLYFORM) || Me.HasAura(NORMAL_FLYFORM),
                              new Action(ret => Lua.DoString("CancelShapeshiftForm()"))
                    ),

                new Decorator(ret => Me.Mounted,
                              new Sequence(
                                  new Action(ret => Lua.DoString("Dismount()")),
                                  new Wait(1, new ActionIdle())
                                  )),

                new Decorator(ret => Me.Mounted,
                              new Sequence(
                                  new Action(ret => Mount.Dismount()),
                                  new Wait(1, new ActionIdle())
                                  )),

                new Decorator(ret => Me.IsFalling,
                              new Wait(2, new ActionIdle())
                    )
                );
        }

        public static Composite PathMakerBehavior()
        {
            return new PrioritySelector(

                new Decorator(ret => ProfileManager.CurrentProfile.GrindArea == null,
                              new Action(ret =>
                                  {
                                      RevriteAndReLoadProfile();
                                      return RunStatus.Failure;
                                  })
                    ),

                new Decorator(ret => ProfileManager.CurrentProfile.GrindArea.CurrentHotSpot == null,
                              new Sequence(
                                  PetBuddy.adlog("[Mover] Current hotspot is null"),
                                  new Action(ret =>
                                      {
                                          ProfileManager.CurrentProfile.GrindArea.CycleToNearest();
                                          return RunStatus.Failure;
                                      })
                                  )),

                new Decorator(ret => Me.Location.Distance(ProfileManager.CurrentProfile.GrindArea.CurrentHotSpot) <= 10 && !Flightor.IsGeneratingPath,
                              new Sequence(
                                  PetBuddy.adlog("[Mover] Let's check next hotspot"),
                                  new Action(ret =>
                                      {
                                          ProfileManager.CurrentProfile.GrindArea.GetNextHotspot();
                                          return RunStatus.Failure;
                                      })
                                  )),

                new Decorator(ret => ProfileManager.CurrentProfile.GrindArea.CurrentHotSpot != null,
                              new Sequence(
                                  PetBuddy.adlog("[Mover] MoveTo:{0}  Distance:{1}", ProfileManager.CurrentProfile.GrindArea.CurrentHotSpot.ToString(), Me.Location.Distance(ProfileManager.CurrentProfile.GrindArea.CurrentHotSpot)),
                                  new Action(ret => navSelector = NavSelector.PROFILE),
                                  MoveToTargetNavPoint()
                                  ))
            );
        }
    }
}
